#pragma once

#include <glib/gtypes.h>

namespace BuildNG
{
  class AsyncRingBufferTests;

  class AsyncRingBuffer
  {
    friend class AsyncRingBufferTests;

  public:
    AsyncRingBuffer(int size);
    ~AsyncRingBuffer();

    bool          push(const void *ptr,int size,void (*copy_func)(void *dest,const void *src),void (dtor_func)(void *ptr));    
    void*         pop_acquire();
    void          pop_release(void *ptr);

  private:
    template <class T>
    static void copy_wrapper(void *dest,const void *src)
    {
      new (dest) T(*(T*)src);
    }

    template <class T>
    static void dtor_wrapper(void *data)
    {
      ((T*)data)->~T();
    }

  public:

    template <class T>
    bool          push(const T &v)
    {
      return push(&v,sizeof(T),copy_wrapper<T>,dtor_wrapper<T>);
    }

  private:
    struct Header
    {
      int         size;
      void        (*dtor)(void *ptr);
    };

    struct Item : Header
    {
      guint8      data[1];
    };

    gint          write_ptr;
    gint          pop_ptr;
    gint          free_ptr;

    guint8*       blob;
    int           blob_size;
  };
}
